package com.utils;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

/**
 * 通用工具类
 * 
 * @author zongtt
 * 
 */
public class Utils {

	private final static DecimalFormat df = new DecimalFormat();
	private final static DecimalFormat dfString = new DecimalFormat();
	static {
		df.setMinimumFractionDigits(0);
		df.setMaximumFractionDigits(0);
		df.setGroupingUsed(false);
		dfString.setMinimumFractionDigits(0);
		dfString.setMaximumFractionDigits(2);
		dfString.setGroupingUsed(false);
	}

	private static Logger log = Logger.getLogger(Utils.class);

	/**
	 * 获取用户真实的IP
	 * @author zongtt
	 * @param request
	 * @return
	 * 2011-6-27 下午04:13:25
	 */
	public static String getRemortIP(HttpServletRequest request) {
		
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}

		return ip;
	}
	
	public static boolean isNumber(String s){
		if(StringUtils.isNotBlank(s))
			return s.matches("[\\d.]+");
		
		return false;
	}
	
	/**
	 * 获取本机ip
	 * @return
	 */
	public static String getLocalIp() {
		String localip = null;// 本地IP，如果没有配置外网IP则返回它
		String netip = null;// 外网IP

		Enumeration<NetworkInterface> netInterfaces;
		try {
			netInterfaces = NetworkInterface.getNetworkInterfaces();
			InetAddress ip = null;
			boolean finded = false;// 是否找到外网IP
			while (netInterfaces.hasMoreElements() && !finded) {
				NetworkInterface ni = netInterfaces.nextElement();
				Enumeration<InetAddress> address = ni.getInetAddresses();
				while (address.hasMoreElements()) {
					ip = address.nextElement();
					if (!ip.isSiteLocalAddress() 
							&& !ip.isLoopbackAddress() 
							&& ip.getHostAddress().indexOf(":") == -1) {// 外网IP
						netip = ip.getHostAddress();
						finded = true;
						break;
					} else if (ip.isSiteLocalAddress() 
							&& !ip.isLoopbackAddress() 
							&& ip.getHostAddress().indexOf(":") == -1) {// 内网IP
						localip = ip.getHostAddress();
					}
				}
			}
		} catch (SocketException e) {
			e.printStackTrace();
		}
		
	
		if (StringUtils.isNotBlank(netip)) {
			log.info("local ip address:"+netip);
			return netip;
		} else {
			log.info("local ip address:"+localip);
			return localip;
		}
	}
	
	/**
	 * 获取指定位数的随机密码
	 * @param pwdLen
	 * @return
	 */
	public static String getRandomPwd(int pwdLen){
		
		if(pwdLen < 6){
			return "";
		}
		
		StringBuilder sb = new StringBuilder();
		//密码生成规则去掉O和o
		char[] lowerStr = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
				'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v',
				'w', 'x', 'y', 'z' };

		char[] upperStr = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
				'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
				'W', 'X', 'Y', 'Z' };

		char[] dataStr = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };

		SecureRandom random = null;

		try {
			random = SecureRandom.getInstance("SHA1PRNG");
		} catch (NoSuchAlgorithmException e) {
			random = new SecureRandom();
		}
		
//		random.setSeed(random.generateSeed(20));
		random.setSeed(generateAlternativeSeed());
		
		Map<Integer, Character> charMap = new HashMap<Integer, Character>();
		Character rand = null;
		// 确保三类字符数量大致平均。
		for(int i = 0; i < pwdLen; i ++){
			if(i < pwdLen / 3){
				int lower = random.nextInt(24);
				rand = lowerStr[lower];
			}else if(i >= pwdLen * 2 / 3){
				int upper = random.nextInt(25);
				rand = upperStr[upper];
			}else{
				int data = random.nextInt(10);
				rand = dataStr[data];
			}
			charMap.put(i, rand);
		}
		
		// 将获取的字符顺序随机打乱。
		int len = pwdLen;
		while(len > 0){
			int x = random.nextInt(pwdLen);
			rand = charMap.get(x);
			if(rand != null){
				sb.append(rand.charValue());
				charMap.remove(x);
				len --;
			}
		}
		
		return sb.toString();
	}
	
	/**
	 * 生成数字字符串
	 * @param length
	 */
	public static String getRandomNumber(int length) {
		int[] array = {0,1,2,3,4,5,6,7,8,9};
		Random rand = new Random();
		for (int i = 10; i > 1; i--) {
		    int index = rand.nextInt(i);
		    int tmp = array[index];
		    array[index] = array[i - 1];
		    array[i - 1] = tmp;
		}
		int result = 0;
		for(int i = 0; i < length; i++) {
			result = result * 10 + array[i];
		}
		return String.valueOf(result) ;
	}
	
	private static byte[] generateAlternativeSeed() {
        try {
            ByteArrayOutputStream bout = new ByteArrayOutputStream();
            DataOutputStream out = new DataOutputStream(bout);

            // milliseconds
            out.writeLong(System.currentTimeMillis());

            // nanoseconds if available
            try {
                Method m = System.class.getMethod("nanoTime");
                if (m != null) {
                    Object o = m.invoke(null);
                    out.writeUTF(o.toString());
                }
            } catch (Exception e) {
                // nanoTime not found, this is ok (only exists for JDK 1.5 and higher)
            }

            // memory
            out.writeInt(new Object().hashCode());
            Runtime runtime = Runtime.getRuntime();
            out.writeLong(runtime.freeMemory());
            out.writeLong(runtime.maxMemory());
            out.writeLong(runtime.totalMemory());

            // timing (a second thread is already running usually)
            for (int j = 0; j < 16; j++) {
                int i = 0;
                long end = System.currentTimeMillis();
                while (end == System.currentTimeMillis()) {
                    i++;
                }
                out.writeInt(i);
            }

            out.close();
            return bout.toByteArray();
        } catch (IOException e) {
            return new byte[1];
        }
    }
	
	/**
	 * 获取参数串
	 * 
	 * @param paramMap
	 * @return
	 */
	public static String getQueryString(Map paramMap) {

		List<String> paramName = new ArrayList<String>(paramMap.keySet());
		String queryString = "";

		StringBuffer sb = new StringBuffer();

		for (String name : paramName) {
			if (!"returnUrl".equals(name)) {
				
				String[] valueArray = (String[]) paramMap.get(name);
				
				for (String value : valueArray) {
					sb.append("&").append(name).append("=").append(value);
				}
			}

		}

		if (sb.length() > 0) {
			queryString = "?" + sb.substring(1);
		}

		return queryString;
	}
	
	/**
	 * 将传入实体类的属性值为null且该属性为字符串类型，则将其置为空字符串
	 * 
	 * @param obj
	 * @throws Exception
	 */
	public static void setEmptyForNull(Object obj) throws Exception {

		Class clazz = obj.getClass();

		Field[] fields = clazz.getDeclaredFields();

		for (Field field : fields) {

			String fieldName = field.getName();

			String methodSuffix = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);

			String getMethod = "get" + methodSuffix;

			if (containMethod(clazz, getMethod)) {

				Method method = clazz.getMethod(getMethod);

				if ("java.lang.String".equalsIgnoreCase(method.getReturnType().getName())) {

					Object value = method.invoke(obj);

					if (value == null) {
						String setMethod = "set" + methodSuffix;
						if (containMethod(clazz, setMethod)) {
							method = clazz.getMethod(setMethod, String.class);
							method.invoke(obj, "");
						}
					}

				}

			}
		}

	}

	/**
	 * 将传入实体类的属性值为null且该属性为字符串类型，则将其置为空字符串
	 * 
	 * @param obj
	 */
	public static void setEmptyNoException(Object obj) {

		try {
			setEmptyForNull(obj);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	/**
	 * 转为整数
	 * 
	 * @param str
	 * @return
	 */
	public static Integer toInteger(String str) {
		if (str == null)
			return 0;
		try {
			return Integer.parseInt(str);
		} catch (NumberFormatException e) {
			return 0;
		}
	}

	/**
	 * double转为int
	 * 
	 * @param d
	 * @return
	 */
	public static int doubleToInt(Double d) {
		if (d == null)
			return 0;
		try {
			String vp = df.format(d);
			if (vp == null)
				return 0;
			return Integer.parseInt(vp);
		} catch (Exception e) {
			return 0;
		}
	}

	/**
	 * double转为String
	 * 
	 * @param d
	 * @return
	 */
	public static String doubleToString(Double d) {
		if (d == null)
			return null;
		try {
			return dfString.format(d);
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * 查询该类是否包含指定的方法
	 * 
	 * @param clazz
	 * @param methodName
	 * @return
	 */
	public static boolean containMethod(Class clazz, String methodName) {

		Method[] methods = clazz.getDeclaredMethods();

		for (Method method : methods) {

			if (method.getName().equals(methodName)) {
				return true;
			}
		}

		return false;
	}

	/**
	 * 对比两个javaBean属性的值是否相等
	 * 
	 * @param o1
	 *            the first object to be compared.
	 * @param o2
	 *            the second object to be compared.
	 * @return 属性值对比结果Map,key为属性的Name,value为对比结果(true表示属性相同)
	 */
/*	public static Map<String, Boolean> compareProperties(Object o1, Object o2) {
		HashMap<String, Boolean> result = new HashMap<String, Boolean>();
		BeanMap bm1 = new BeanMap(o1);
		BeanMap bm2 = new BeanMap(o2);
		Iterator<?> it1 = bm1.entryIterator();
		while (it1.hasNext()) {
			boolean equals = false;
			Map.Entry<?, ?> entry = (Map.Entry<?, ?>) it1.next();
			Object k1 = entry.getKey();
			Object v1 = entry.getValue();
			if (bm2.containsKey(k1)) {
				Object v2 = bm2.get(k1);
				if (v2 == null) {
					equals = (v1 == null);
				} else {
					equals = v2.equals(v1);
				}
			}
			result.put(String.valueOf(k1), Boolean.valueOf(equals));
		}
		return result;
	}*/
	
	/**
	 * 传入两个对象返回字段值不同的Map .
	 * @param o1 
	 * @param o2
	 * @param compareFields
	 * @return 返回字段值不同的字段 
	 */
	/*public static Map<String,Object[]> diffProps(Object o1, Object o2,List<String> compareFields) {
		HashMap<String, Object[]> result = new HashMap<String, Object[]>();
		BeanMap bm1 = new BeanMap(o1);
		BeanMap bm2 = new BeanMap(o2);
		Iterator<?> it1 = bm1.entryIterator();
		while (it1.hasNext()) {
			boolean equals = false;
			Map.Entry<?, ?> entry = (Map.Entry<?, ?>) it1.next();
			Object k1 = entry.getKey();
			if(!compareFields.contains(k1)) {
				continue ;
			}
			Object v1 = entry.getValue();
			Object v2 = null;
			if (bm2.containsKey(k1)) {
				v2 = bm2.get(k1);
				if (v2 == null) {
					if(v1==null){
						equals = true;
					}else{
						if(v1 instanceof String){
							equals = StringUtils.equals(StringUtils.trimToEmpty((String)v1), StringUtils.trimToEmpty((String)v2));
						}else{
							equals = false;
						}
					}
					//modify by liyang 2011-8-15
					if(v1 instanceof String) {
						equals = ((String)v1).isEmpty();
					} else {
						equals = (v1 == null);
					}
				} else {
					if(v1==null){
						if(v2 instanceof String){
							equals = StringUtils.equals(StringUtils.trimToEmpty((String)v1), StringUtils.trimToEmpty((String)v2));
						}else{
							equals = false;
						}
					}else{
						if(v2 instanceof String){
							equals = StringUtils.equals(StringUtils.trimToEmpty((String)v1), StringUtils.trimToEmpty((String)v2));
						}else if(v2 instanceof Date){
							String d1 = DateUtil.dateToString((Date) v1, DateUtil.DATE_FORMAT_YYYY_MM_DD_HH_MM_SS);
							String d2 = DateUtil.dateToString((Date)v2, DateUtil.DATE_FORMAT_YYYY_MM_DD_HH_MM_SS);
							equals = StringUtils.equals(d1,d2);
						}else{
							equals = v2.equals(v1);
						}
					}
					//modify by liyang 2011-8-15
					//equals = v2.equals(v1);
				}
			}
			if (!equals) {
				Object[] diffProp = {v1,v2};
				result.put(String.valueOf(k1), diffProp);
			}
		}
		return result;
	}*/
	
	/**
	 * 将对象转换为字符串,如果对象为空则返回空串.
	 * @param value Object对象
	 */
	public static String toString(Object value) {
		String result = "";
		if (value != null)
			result = value.toString();
		return result;
	}
	
	/**
	 * 将Number对象按传入的pattern转换成字符串,如果传入的是非Number类型则返回空串.
	 * @param value 
	 * @param pattern
	 */
	public static String numberToString(Object value,String pattern) {
		String result = "";
		if(value != null) {
			if(value instanceof Number) {
				DecimalFormat decimalFormat =new DecimalFormat(pattern);
				result = decimalFormat.format(((Number)value));
			}
		}
		return result;
	}
	
	/**
	 * 将Number对象转换成整数型字符串,如果传入的是非Number类型则返回空串.
	 * @param value
	 */
	public static String numberToString(Object value) {
		return numberToString(value, "#");
	}
	
	private static double rad(double d) {
		return d * Math.PI / 180.0;
	}

	/**
	 * 计算两个经纬度之间的距离
	 * 
	 * @author zongtt
	 * @param lat1
	 * @param lng1
	 * @param lat2
	 * @param lng2
	 * @return 2011-2-16 上午07:59:19
	 */
	public static double getDistance(double lat1, double lng1, double lat2, double lng2) {
		double radLat1 = rad(lat1);
		double radLat2 = rad(lat2);
		double a = radLat1 - radLat2;
		double b = rad(lng1) - rad(lng2);
		double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
		//s = s * Constant.EARTH_RADIUS;
		s = Math.round(s * 10000) / 10000;
		return s;
	}

	/**
	 * 根据属性获取get方法
	 * @author zongtt
	 * @param attr
	 * @return
	 * 2011-4-19 上午06:36:10
	 */
	/*public static String getGetter(String attr){
		
		if (StringUtils.isEmpty(attr))
			return null;
		String methodName = null;
		try {
			methodName = "get" + attr.trim().substring(0, 1).toUpperCase() + attr.trim().substring(1);
		} catch (Exception e) {
		}
		return methodName;
	}*/
	
	/**
	 * 根据属性获取set方法
	 * @author zongtt
	 * @param attr
	 * @return
	 * 2011-4-19 上午06:36:10
	 */
	/*public static String getSetter(String attr) {
		if (StringUtils.isEmpty(attr))
			return null;
		String methodName = null;
		try {
			methodName = "set" + attr.trim().substring(0, 1).toUpperCase() + attr.trim().substring(1);
		} catch (Exception e) {
		}
		return methodName;
	}*/
	
	
	/**
	 * 将16进制转换为二进制
	 * 
	 * @param hexStr
	 * @return
	 */
	public static byte[] parseHexStr2Byte(String hexStr) {
		if (hexStr.length() < 1)
			return null;
		byte[] result = new byte[hexStr.length() / 2];
		for (int i = 0; i < hexStr.length() / 2; i++) {
			int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
			int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2),
					16);
			result[i] = (byte) (high * 16 + low);
		}
		return result;
	}

	/**
	 * 将二进制转换成16进制
	 * 
	 * @param buf
	 * @return
	 */
	public static String parseByte2HexStr(byte buf[]) {
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < buf.length; i++) {
			String hex = Integer.toHexString(buf[i] & 0xFF);
			if (hex.length() == 1) {
				hex = '0' + hex;
			}
			sb.append(hex.toUpperCase());
		}
		return sb.toString();
	}
	
	/**
	 * 生僻字验证
	 * @param name
	 * @return true：生僻字，false：非生僻字
	 */
	public static boolean isRareWord(String name) {
		if (StringUtils.isBlank(name)) {
			return false;
		}
		for (int j = 0; j < name.length(); j++) {
			try {
				if ((name.charAt(j) + "").getBytes("gb2312").length != (name.charAt(j) + "").getBytes("gbk").length) {
					return true;
				}
			} catch (Exception e) {
				return false;
			}
		}
		return false;
	}
	
	/**
	 * 生僻字检查提醒
	 * @param name 乘客姓名
	 * @return 不含生僻字，没有提醒。如果含有生僻字，返回对应提醒。
	 */
	public static String checkRareName(String name) {
		if (StringUtils.isBlank(name)) {
			return null;
		}
		
		if (StringUtils.contains(name, ".")) {
			return "姓名中的“ .” 不可输入，如“穆罕默德.松赞干布”，请输入“穆罕默德松赞干布”，“Harry.Potter”请输入“Harry/Potter”。";
		}
		else {
			//是否英文姓名
			if (isEnglish(name)) {
				return "英文字母的姓名，姓与名之间需用斜线（/）分开，最多只可有一个斜线，并且姓不少于2个字母。";
			}
			else {
				//是否全部英文
				if (StringUtils.contains(name, "/")) {
					String [] checkNames = name.split("/");
					
					boolean ifAllEnglish = true;
					if (checkNames != null && checkNames.length > 1) {
						for (int i = 0; i < checkNames.length; i++) {
							if (!isEnglish(checkNames[i])) {
								ifAllEnglish = false;
								break;
							}
						}
					}
					
					if (!ifAllEnglish || ifAllEnglish && (checkNames.length != 2 || checkNames[0].length() < 2)) {
						return "英文字母的姓名，姓与名之间需用斜线（/）分开，最多只可有一个斜线，并且姓不少于2个字母。";
					}
				}
				else {
					for (int i = 0; i < name.length(); i++) {
						char checkName = name.charAt(i);
						
						//是否中英文姓名
						if (checkName >= 'A' && checkName <= 'Z'
								|| checkName >= 'a' && checkName <= 'z') {
							String enName = name.substring(i);
							if (!isEnglish(enName)) {
								return "中英文字母的姓名，英文字母之后不可出现汉字。";
							}
							break;
						}
						
						String rareName = checkName + "";
						if (StringUtils.isNumeric(rareName)) {
							return "姓名中不允许含数字。";
						}
						
						int m = 0, n = 0; 
						try {
							m = rareName.getBytes("gb2312").length;
							n = rareName.getBytes("gbk").length;
						} catch (Exception e) {
							return null;
						}
						
						//是否中文生僻字
						if (m != n) {
							String content = "您的姓名中包含生僻字“" + checkName;
							if (i == 0) {
								return content + "”，请将姓名以拼音替代。如：彧青云，请按“YU/QINGYUN”格式填写。";
							} else if (i == name.length()-1) {
								return content + "”，请将姓名以拼音替代。如：云青彧，请按“云青YU”格式填写。";
							} else {
								return content + "”，请将姓名以拼音替代。如：云彧青，请按“云YUQING”格式填写。";
							}
						}
					}
				}
			}
		}
		return null;
	}
	
	/**
	 * 是否全为英文
	 * @param name
	 * @return
	 */
	public static boolean isEnglish(String name) {
		if (StringUtils.isBlank(name)) {
			return false;
		}
		
		boolean ifEnglish = true;//是否英文姓名
		for (int i = 0; i < name.length(); i++) {
			char checkName = name.charAt(i);
			if (!(checkName >= 'A' && checkName <= 'Z')
					&& !(checkName >= 'a' && checkName <= 'z')) {
				ifEnglish = false;
			}
		}
		return ifEnglish;
	}
	
	/**
	 * 验证邮箱
	 * @param email
	 * @return
	 */
	public static boolean isEmail(String email){
        Pattern p = Pattern.compile("\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*");
        Matcher m = p.matcher(email);
        return m.find();
    }
	
	/**
	 * 验证手机号(兼容188、189段)
	 * @param mobile
	 * @return
	 */
	public static boolean isMobile(String mobile){
//		 Pattern p = Pattern.compile("^\\d{11}$");
		 Pattern p = Pattern.compile("^(13[0-9]|14[0-9]|15[0-9]|18[0-9])\\d{8}$");
//		 Pattern p = Pattern.compile("^(13[0-9]|15[0|3|6|7|8|9]|18[8|9])\\d{8}$");
		 Matcher m = p.matcher(mobile);
	     return m.find();
	}
	
	/**
	 * 获取webservice客户端IP
	 * 
	 * @return
	 */
	/*public static String getWsIp(WebServiceContext context){
		try{
			MessageContext ctx = context.getMessageContext();
			HttpServletRequest request = (HttpServletRequest)
			ctx.get(AbstractHTTPDestination.HTTP_REQUEST);
			String IP = request.getHeader("x-forwarded-for");
			if(StringUtils.isEmpty(IP)) { 
			   IP = request.getRemoteAddr(); 
			}
			return IP;
		} catch(Exception e){
			log.error(e);
			return null;
		}
	}*/
	
	/**
	 * 验证ip是否受限
	 * 参数名为空的情况下则受限
	 * @param context
	 * @param configParam config文件中的参数名
	 * @return
	 */
	public static boolean isLimitedIp(String visitIp, String whiteIp){
		
		if(StringUtils.isBlank(whiteIp)||StringUtils.isBlank(visitIp)){
			return false;
		}
		// 验证请求IP是否在白名单中
		if (whiteIp.indexOf(visitIp) == -1) {
			return true;
		}
		
		return false;
	}
	
	public static void main(String[] args) {
		System.out.println(getRandomNumber(8));
	}
	
}